home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xmball / Mball.c < prev    next >
C/C++ Source or Header  |  1996-03-10  |  52KB  |  1,679 lines

  1. /*
  2. # X-BASED MASTERBALL(tm)
  3. #
  4. #  Mball.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Mball */
  27.  
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <math.h>
  31. #ifdef VMS
  32. #define M_PI 3.14159265358979323846
  33. #endif
  34. #ifdef VMS
  35. #include <unixlib.h>
  36. #else
  37. #ifndef apollo
  38. #include <unistd.h>
  39. #endif
  40. #endif
  41. #include <X11/IntrinsicP.h>
  42. #include <X11/Intrinsic.h>
  43. #include <X11/StringDefs.h>
  44. #include <X11/CoreP.h>
  45. #include "MballP.h"
  46.  
  47. #ifndef DATAFILE
  48. #define DATAFILE "/usr/games/lib/mball.data"
  49. #endif
  50.  
  51. static void InitializeMball();
  52. static void ExposeMball();
  53. static void ResizeMball();
  54. static void DestroyMball();
  55. static Boolean SetValuesMball();
  56. static void QuitMball();
  57. static void PracticeMball();
  58. static void PracticeMballMaybe();
  59. static void RandomizeMball();
  60. static void RandomizeMballMaybe();
  61. static void GetMball();
  62. static void WriteMball();
  63. static void UndoMball();
  64. static void SolveMball();
  65. static void IncrementMball();
  66. static void DecrementMball();
  67. static void OrientizeMball();
  68. static void Wedge2ModeMball();
  69. static void Wedge4ModeMball();
  70. static void Wedge6ModeMball();
  71. static void Wedge8ModeMball();
  72. static void MoveMballTl();
  73. static void MoveMballTop();
  74. static void MoveMballTr();
  75. static void MoveMballLeft();
  76. static void MoveMballCw();
  77. static void MoveMballRight();
  78. static void MoveMballBl();
  79. static void MoveMballBottom();
  80. static void MoveMballBr();
  81. static void MoveMballCcw();
  82. static void MoveMballInput();
  83. static void SelectMball();
  84. static void ReleaseMball();
  85. static void GetColor();
  86. static void MoveControlCb();
  87. static void CheckWedges();
  88. static void ResetWedges();
  89. static void ResizeWedges();
  90. static int SelectWedges();
  91. static int PositionWedges();
  92. static void MoveNoWedges();
  93. static void PracticeWedges();
  94. static void RandomizeWedges();
  95. static void MoveWedges();
  96. /* rcd : row, column, or diagonal */
  97. static void SwapWedges();
  98. static void DrawFrame();
  99. static void DrawWedge();
  100. static void DrawSector();
  101. static void DrawRadar();
  102. static void DrawSect();
  103. static void LetterPosition();
  104. static void OffsetSect();
  105. static void XFillSector();
  106. static void XDrawSector();
  107.  
  108. #ifdef DEBUG
  109. static void PrintMball();
  110. static void PrintWedge();
  111. static void PrintRow();
  112. #endif
  113.  
  114. static char defaultTranslationsMball[] =
  115.   "<KeyPress>q: Quit()\n\
  116.    Ctrl<KeyPress>C: Quit()\n\
  117.    <KeyPress>KP_Divide: MoveCcw()\n\
  118.    <KeyPress>Home: MoveTl()\n\
  119.    <KeyPress>KP_7: MoveTl()\n\
  120.    <KeyPress>R7: MoveTl()\n\
  121.    <KeyPress>Up: MoveTop()\n\
  122.    <KeyPress>KP_8: MoveTop()\n\
  123.    <KeyPress>R8: MoveTop()\n\
  124.    <KeyPress>Prior: MoveTr()\n\
  125.    <KeyPress>KP_9: MoveTr()\n\
  126.    <KeyPress>R9: MoveTr()\n\
  127.    <KeyPress>Left: MoveLeft()\n\
  128.    <KeyPress>KP_4: MoveLeft()\n\
  129.    <KeyPress>R10: MoveLeft()\n\
  130.    <KeyPress>Begin: MoveCw()\n\
  131.    <KeyPress>KP_5: MoveCw()\n\
  132.    <KeyPress>R11: MoveCw()\n\
  133.    <KeyPress>Right: MoveRight()\n\
  134.    <KeyPress>KP_6: MoveRight()\n\
  135.    <KeyPress>R12: MoveRight()\n\
  136.    <KeyPress>End: MoveBl()\n\
  137.    <KeyPress>KP_1: MoveBl()\n\
  138.    <KeyPress>R13: MoveBl()\n\
  139.    <KeyPress>Down: MoveBottom()\n\
  140.    <KeyPress>KP_2: MoveBottom()\n\
  141.    <KeyPress>R14: MoveBottom()\n\
  142.    <KeyPress>Next: MoveBr()\n\
  143.    <KeyPress>KP_3: MoveBr()\n\
  144.    <KeyPress>R15: MoveBr()\n\
  145.    <KeyPress>p: Practice()\n\
  146.    <Btn1Down>: Select()\n\
  147.    <Btn1Up>: Release()\n\
  148.    <Btn2Down>(2+): Practice()\n\
  149.    <Btn2Down>: PracticeMaybe()\n\
  150.    <KeyPress>r: Randomize()\n\
  151.    <Btn3Down>(2+): Randomize()\n\
  152.    <Btn3Down>: RandomizeMaybe()\n\
  153.    <KeyPress>g: Get()\n\
  154.    <KeyPress>w: Write()\n\
  155.    <KeyPress>u: Undo()\n\
  156.    <KeyPress>s: Solve()\n\
  157.    <KeyPress>i: Increment()\n\
  158.    <KeyPress>d: Decrement()\n\
  159.    <KeyPress>o: Orientize()\n\
  160.    <KeyPress>2: Wedge2()\n\
  161.    <KeyPress>4: Wedge4()\n\
  162.    <KeyPress>6: Wedge6()\n\
  163.    <KeyPress>8: Wedge8()";
  164.  
  165. static XtActionsRec actionsListMball[] =
  166. {
  167.   {"Quit", (XtActionProc) QuitMball},
  168.   {"MoveCcw", (XtActionProc) MoveMballCcw},
  169.   {"MoveTl", (XtActionProc) MoveMballTl},
  170.   {"MoveTop", (XtActionProc) MoveMballTop},
  171.   {"MoveTr", (XtActionProc) MoveMballTr},
  172.   {"MoveLeft", (XtActionProc) MoveMballLeft},
  173.   {"MoveCw", (XtActionProc) MoveMballCw},
  174.   {"MoveRight", (XtActionProc) MoveMballRight},
  175.   {"MoveBl", (XtActionProc) MoveMballBl},
  176.   {"MoveBottom", (XtActionProc) MoveMballBottom},
  177.   {"MoveBr", (XtActionProc) MoveMballBr},
  178.   {"Select", (XtActionProc) SelectMball},
  179.   {"Release", (XtActionProc) ReleaseMball},
  180.   {"Practice", (XtActionProc) PracticeMball},
  181.   {"PracticeMaybe", (XtActionProc) PracticeMballMaybe},
  182.   {"Randomize", (XtActionProc) RandomizeMball},
  183.   {"RandomizeMaybe", (XtActionProc) RandomizeMballMaybe},
  184.   {"Get", (XtActionProc) GetMball},
  185.   {"Write", (XtActionProc) WriteMball},
  186.   {"Undo", (XtActionProc) UndoMball},
  187.   {"Solve", (XtActionProc) SolveMball},
  188.   {"Increment", (XtActionProc) IncrementMball},
  189.   {"Decrement", (XtActionProc) DecrementMball},
  190.   {"Orientize", (XtActionProc) OrientizeMball},
  191.   {"Wedge2", (XtActionProc) Wedge2ModeMball},
  192.   {"Wedge4", (XtActionProc) Wedge4ModeMball},
  193.   {"Wedge6", (XtActionProc) Wedge6ModeMball},
  194.   {"Wedge8", (XtActionProc) Wedge8ModeMball}
  195. };
  196.  
  197. static XtResource resourcesMball[] =
  198. {
  199.   {XtNwedgeColor0, XtCLabel, XtRString, sizeof(String),
  200.    XtOffset(MballWidget, mball.wedgeName[0]), XtRString, "Yellow"},
  201.   {XtNwedgeColor1, XtCLabel, XtRString, sizeof(String),
  202.    XtOffset(MballWidget, mball.wedgeName[1]), XtRString, "Blue"},
  203.   {XtNwedgeColor2, XtCLabel, XtRString, sizeof(String),
  204.    XtOffset(MballWidget, mball.wedgeName[2]), XtRString, "Red"},
  205.   {XtNwedgeColor3, XtCLabel, XtRString, sizeof(String),
  206.    XtOffset(MballWidget, mball.wedgeName[3]), XtRString, "Magenta"},
  207.   {XtNwedgeColor4, XtCLabel, XtRString, sizeof(String),
  208.    XtOffset(MballWidget, mball.wedgeName[4]), XtRString, "Green"},
  209.   {XtNwedgeColor5, XtCLabel, XtRString, sizeof(String),
  210.    XtOffset(MballWidget, mball.wedgeName[5]), XtRString, "Orange"},
  211.   {XtNwedgeColor6, XtCLabel, XtRString, sizeof(String),
  212.    XtOffset(MballWidget, mball.wedgeName[6]), XtRString, "Cyan"},
  213.   {XtNwedgeColor7, XtCLabel, XtRString, sizeof(String),
  214.    XtOffset(MballWidget, mball.wedgeName[7]), XtRString, "DarkGreen"},
  215.   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  216.    XtOffset(MballWidget, mball.foreground), XtRString, XtDefaultForeground},
  217.   {XtNpieceBorder, XtCColor, XtRPixel, sizeof(Pixel),
  218.    XtOffset(MballWidget, mball.borderColor), XtRString, XtDefaultForeground},
  219.   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  220.    XtOffset(MballWidget, core.width), XtRString, "200"},
  221.   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  222.    XtOffset(MballWidget, core.height), XtRString, "400"},
  223.   {XtNmono, XtCMono, XtRBoolean, sizeof(Boolean),
  224.    XtOffset(MballWidget, mball.mono), XtRString, "FALSE"},
  225.   {XtNwedges, XtCWedges, XtRInt, sizeof(int),
  226.    XtOffset(MballWidget, mball.wedges), XtRString, "8"}, /*DEFAULTWEDGES*/
  227.   {XtNrings, XtCRings, XtRInt, sizeof(int),
  228.    XtOffset(MballWidget, mball.rings), XtRString, "4"}, /*DEFAULTRINGS*/
  229.   {XtNorient, XtCOrient, XtRBoolean, sizeof(Boolean),
  230.    XtOffset(MballWidget, mball.orient), XtRString, "FALSE"}, /*DEFAULTORIENT*/
  231.   {XtNpractice, XtCPractice, XtRBoolean, sizeof(Boolean),
  232.    XtOffset(MballWidget, mball.practice), XtRString, "FALSE"}, /*DEFAULTPRACTICE*/
  233.   {XtNstart, XtCBoolean, XtRBoolean, sizeof(Boolean),
  234.    XtOffset(MballWidget, mball.started), XtRString, "FALSE"},
  235.   {XtNselectCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  236.    XtOffset(MballWidget, mball.select), XtRCallback, NULL}
  237. };
  238.  
  239. MballClassRec mballClassRec =
  240. {
  241.   {
  242.     (WidgetClass) &widgetClassRec,    /* superclass */
  243.     "Mball",                /* class name */
  244.     sizeof(MballRec),            /* widget size */
  245.     NULL,                /* class initialize */
  246.     NULL,                /* class part initialize */
  247.     FALSE,                /* class inited */
  248.     InitializeMball,            /* initialize */
  249.     NULL,                /* initialize hook */
  250.     XtInheritRealize,            /* realize */
  251.     actionsListMball,            /* actions */
  252.     XtNumber(actionsListMball),        /* num actions */
  253.     resourcesMball,            /* resources */
  254.     XtNumber(resourcesMball),        /* num resources */
  255.     NULLQUARK,                /* xrm class */
  256.     TRUE,                /* compress motion */
  257.     TRUE,                /* compress exposure */
  258.     TRUE,                /* compress enterleave */
  259.     TRUE,                /* visible interest */
  260.     DestroyMball,            /* destroy */
  261.     ResizeMball,            /* resize */
  262.     ExposeMball,            /* expose */
  263.     SetValuesMball,            /* set values */
  264.     NULL,                /* set values hook */
  265.     XtInheritSetValuesAlmost,        /* set values almost */
  266.     NULL,                /* get values hook */
  267.     NULL,                /* accept focus */
  268.     XtVersion,                /* version */
  269.     NULL,                /* callback private */
  270.     defaultTranslationsMball,        /* tm table */
  271.     NULL,                /* query geometry */
  272.     NULL,                /* display accelerator */
  273.     NULL                /* extension */
  274.   },
  275.   {
  276.     0                    /* ignore */
  277.   }
  278. };
  279.  
  280. static int mapDirToWedge[(MAXWEDGES - MINWEDGES) / 2 + 1][COORD] = 
  281. {
  282.   {0, 4, 4, 4,  0, 4, 4, 4},
  283.   {0, 4, 1, 4,  0, 4, 1, 4},
  284.   {0, 1, 4, 2,  0, 1, 4, 2},
  285.   {0, 1, 2, 3,  0, 1, 2, 3}
  286. };
  287. static int mapWedgeToDir[(MAXWEDGES - MINWEDGES) / 2 + 1][COORD] = 
  288. {
  289.   {0, 4, 8, 8,  8, 8, 8, 8},
  290.   {0, 2, 4, 6,  8, 8, 8, 8},
  291.   {0, 1, 3, 4,  5, 7, 8, 8},
  292.   {0, 1, 2, 3,  4, 5, 6, 7}
  293. };
  294.  
  295. WidgetClass mballWidgetClass = (WidgetClass) &mballClassRec;
  296.  
  297. static void InitializeMball(request, new)
  298.   Widget request, new;
  299. {
  300.   MballWidget w = (MballWidget) new;
  301.   XGCValues values;
  302.   XtGCMask valueMask;
  303.   int wedge;
  304.  
  305.   for (wedge = 0; wedge < MAXWEDGES; wedge++)
  306.     w->mball.mballLoc[wedge] = NULL;
  307.   CheckWedges(w);
  308.   InitMoves();
  309.   ResetWedges(w);
  310.   (void) SRAND(getpid());
  311.   valueMask = GCForeground | GCBackground;
  312.   values.background = w->core.background_pixel;
  313.   values.foreground = w->mball.foreground;
  314.   w->mball.puzzleGC = XtGetGC(new, valueMask, &values);
  315.   values.foreground = w->mball.borderColor;
  316.   w->mball.borderGC = XtGetGC(new, valueMask, &values);
  317.   w->mball.depth = DefaultDepthOfScreen(XtScreen(w));
  318.   valueMask = GCForeground | GCBackground;
  319.   values.foreground = w->core.background_pixel;
  320.   values.background = w->mball.foreground;
  321.   w->mball.inverseGC = XtGetGC(new, valueMask, &values);
  322.   for (wedge = 0; wedge < MAXWEDGES; wedge++)
  323.     GetColor(w, wedge, TRUE);
  324.   ResizeMball(w);
  325. }
  326.  
  327. static void DestroyMball(old)
  328.   Widget old;
  329. {
  330.   MballWidget w = (MballWidget) old;
  331.   int wedge;
  332.  
  333.   for (wedge = 0; wedge < MAXWEDGES; wedge++) {
  334.     XtReleaseGC(old, w->mball.wedgeGC[wedge]);
  335.   }
  336.   XtReleaseGC(old, w->mball.borderGC);
  337.   XtReleaseGC(old, w->mball.puzzleGC);
  338.   XtReleaseGC(old, w->mball.inverseGC);
  339.   XtRemoveCallbacks(old, XtNselectCallback, w->mball.select);
  340. }
  341.  
  342. static void ResizeMball(w)
  343.   MballWidget w;
  344. {
  345.   int tempLength;
  346.  
  347.   w->mball.delta = 4;
  348.   w->mball.vertical = (w->core.height >= w->core.width);
  349.   if (w->mball.vertical)
  350.     tempLength = MIN(w->core.height / 2, w->core.width);
  351.   else
  352.     tempLength = MIN(w->core.height, w->core.width / 2);
  353.   w->mball.mballLength = MAX((tempLength - w->mball.delta + 1) /
  354.     w->mball.wedges, 0);
  355.   w->mball.wedgeLength = w->mball.wedges * w->mball.mballLength;
  356.   w->mball.viewLength = w->mball.wedgeLength + w->mball.delta;
  357.   w->mball.viewMiddle = w->mball.viewLength / 2;
  358.   if (w->mball.vertical) {
  359.     w->mball.puzzleSize.x = w->mball.viewLength - 1;
  360.     w->mball.puzzleSize.y = 2 * w->mball.viewLength - w->mball.delta - 2;
  361.   } else {
  362.     w->mball.puzzleSize.x = 2 * w->mball.viewLength - w->mball.delta - 2;
  363.     w->mball.puzzleSize.y = w->mball.viewLength - 1;
  364.   }
  365.   w->mball.puzzleOffset.x = ((int) w->core.width - w->mball.puzzleSize.x) / 2;
  366.   w->mball.puzzleOffset.y = ((int) w->core.height - w->mball.puzzleSize.y) / 2;
  367.   ResizeWedges(w);
  368. }
  369.  
  370. static void ExposeMball(new, event, region)
  371.   Widget new;
  372.   XEvent *event;
  373.   Region region; /* Not used */
  374. {
  375.   MballWidget w = (MballWidget) new;
  376.  
  377.   if (w->core.visible) {
  378.     DrawFrame(w, w->mball.puzzleGC);
  379.     DrawAllWedges(w);
  380.   }
  381. }
  382.  
  383. static Boolean SetValuesMball(current, request, new)
  384.   Widget current, request, new;
  385. {
  386.   MballWidget c = (MballWidget) current, w = (MballWidget) new;
  387.   XGCValues values;
  388.   XtGCMask valueMask;
  389.   Boolean redraw = FALSE;
  390.   int wedge;
  391.  
  392.   CheckWedges(w);
  393.   if (w->mball.foreground != c->mball.foreground) {
  394.     valueMask = GCForeground | GCBackground;
  395.     values.foreground = w->mball.foreground;
  396.     values.background = w->core.background_pixel;
  397.     XtReleaseGC(new, w->mball.puzzleGC);
  398.     w->mball.puzzleGC = XtGetGC(new, valueMask, &values);
  399.     redraw = TRUE;
  400.   }
  401.   if (w->core.background_pixel != c->core.background_pixel) {
  402.     valueMask = GCForeground | GCBackground;
  403.     values.foreground = w->core.background_pixel;
  404.     values.background = w->mball.foreground;
  405.     XtReleaseGC(new, w->mball.inverseGC);
  406.     w->mball.inverseGC = XtGetGC(new, valueMask, &values);
  407.     redraw = TRUE;
  408.   }
  409.   if (w->mball.borderColor != c->mball.borderColor) {
  410.     valueMask = GCForeground | GCBackground;
  411.     values.foreground = w->mball.borderColor;
  412.     values.background = w->core.background_pixel;
  413.     XtReleaseGC(new, w->mball.borderGC);
  414.     w->mball.borderGC = XtGetGC(new, valueMask, &values);
  415.     redraw = TRUE;
  416.   }
  417.   if (w->mball.mono || w->mball.depth == 1) {
  418.     valueMask = GCForeground | GCBackground;
  419.     values.background = w->core.background_pixel;
  420.     values.foreground = w->mball.foreground;
  421.     for (wedge = 0; wedge < MAXWEDGES; wedge++) {
  422.       XtReleaseGC(new, w->mball.wedgeGC[wedge]);
  423.       w->mball.wedgeGC[wedge] = XtGetGC(new, valueMask, &values);
  424.     }
  425.     redraw = TRUE;
  426.   }
  427.   for (wedge = 0; wedge < MAXWEDGES; wedge++) {
  428.     if (strcmp(w->mball.wedgeName[wedge], c->mball.wedgeName[wedge]))
  429.       GetColor(w, wedge, FALSE);
  430.   }
  431.   if (w->mball.orient != c->mball.orient) {
  432.     ResetWedges(w);
  433.     redraw = TRUE;
  434.   } else if (w->mball.practice != c->mball.practice) {
  435.     ResetWedges(w);
  436.     redraw = TRUE;
  437.   }
  438.   if (w->mball.wedges != c->mball.wedges ||
  439.       w->mball.rings != c->mball.rings) {
  440.     ResetWedges(w);
  441.     ResizeMball(w);
  442.     redraw = TRUE;
  443.   }
  444.   if (w->mball.mballLength != c->mball.mballLength) {
  445.     ResizeMball(w);
  446.     redraw = TRUE;
  447.   }
  448.   return (redraw);
  449. }
  450.  
  451. static void QuitMball(w, event, args, nArgs)
  452.   MballWidget w;
  453.   XEvent *event;
  454.   char *args[];
  455.   int nArgs;
  456. {
  457.   XtCloseDisplay(XtDisplay(w));
  458.   exit(0);
  459. }
  460.  
  461. static void SelectMball(w, event, args, nArgs)
  462.   MballWidget w;
  463.   XEvent *event;
  464.   char *args[];
  465.   int nArgs;
  466. {
  467.   int view, control;
  468.  
  469.   if (SelectWedges(w, event->xbutton.x, event->xbutton.y,
  470.                     &(w->mball.currentWedge), &(w->mball.currentRing), &view)) {
  471.     control = (int) (event->xkey.state & ControlMask);
  472.     if (control || w->mball.practice || !CheckSolved(w))
  473.       DrawSector(w, w->mball.currentWedge, w->mball.currentRing, TRUE);
  474.   } else
  475.     w->mball.currentWedge = -1;
  476. }
  477.  
  478. static void ReleaseMball(w, event, args, nArgs)
  479.   MballWidget w;
  480.   XEvent *event;
  481.   char *args[];
  482.   int nArgs;
  483. {
  484.   int control, wedge, ring, view, i, diff, opp;
  485.   mballCallbackStruct cb;
  486.  
  487.   if (w->mball.currentWedge == -1)
  488.     return;
  489.   DrawSector(w, w->mball.currentWedge, w->mball.currentRing, FALSE);
  490.   control = (int) (event->xkey.state & ControlMask);
  491.   if (!control && !w->mball.practice && CheckSolved(w))
  492.     MoveNoWedges(w);
  493.   else if (SelectWedges(w, event->xbutton.x, event->xbutton.y,
  494.                     &wedge, &ring, &view)) {
  495.     opp = (w->mball.currentWedge + w->mball.wedges / 2) % w->mball.wedges;
  496.     if (ring == w->mball.currentRing) {
  497.       if (wedge == w->mball.currentWedge)
  498.         return;
  499.       if (opp == (wedge + 1) % w->mball.wedges ||
  500.           wedge == (opp + 1) % w->mball.wedges) {
  501.         cb.reason = MBALL_AMBIGUOUS;
  502.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  503.       } else {
  504.         diff = (w->mball.currentWedge - wedge + w->mball.wedges) %
  505.           w->mball.wedges;
  506.         if (diff > w->mball.wedges / 2)
  507.           for (i = 0; i < w->mball.wedges - diff; i++)
  508.             MoveMball(w, wedge, ring, CW, control);
  509.         else
  510.           for (i = 0; i < diff; i++)
  511.             MoveMball(w, wedge, ring, CCW, control);
  512.         if (!control && CheckSolved(w)) {
  513.           cb.reason = MBALL_SOLVED;
  514.           XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  515.         }
  516.       }
  517.     } else if (wedge == w->mball.currentWedge && w->mball.wedges > 2) {
  518.       cb.reason = MBALL_AMBIGUOUS;
  519.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  520.     } else if (opp == (wedge + 1) % w->mball.wedges)
  521.       MoveMball(w, wedge, ring,
  522.         mapWedgeToDir[(w->mball.wedges  - MINWEDGES) / 2]
  523.                      [w->mball.currentWedge], control);
  524.     else if (wedge == (opp + 1) % w->mball.wedges)
  525.       MoveMball(w, wedge, ring,
  526.         mapWedgeToDir[(w->mball.wedges  - MINWEDGES) / 2][wedge], control);
  527.     else
  528.       MoveNoWedges(w);
  529.   }
  530. }
  531.  
  532. static void PracticeMball(w, event, args, nArgs)
  533.   MballWidget w;
  534.   XEvent *event;
  535.   char *args[];
  536.   int nArgs;
  537. {
  538.   PracticeWedges(w);
  539. }
  540.  
  541. static void PracticeMballMaybe(w, event, args, nArgs)
  542.   MballWidget w;
  543.   XEvent *event;
  544.   char *args[];
  545.   int nArgs;
  546. {
  547.   if (!w->mball.started)
  548.     PracticeWedges(w);
  549. }
  550.  
  551. static void RandomizeMball(w, event, args, nArgs)
  552.   MballWidget w;
  553.   XEvent *event;
  554.   char *args[];
  555.   int nArgs;
  556. {
  557.   RandomizeWedges(w);
  558. }
  559.  
  560. static void RandomizeMballMaybe(w, event, args, nArgs)
  561.   MballWidget w;
  562.   XEvent *event;
  563.   char *args[];
  564.   int nArgs;
  565. {
  566.   if (!w->mball.started)
  567.     RandomizeWedges(w);
  568. }
  569.  
  570. static void GetMball(w, event, args, nArgs)
  571.   MballWidget w;
  572.   XEvent *event;
  573.   char *args[];
  574.   int nArgs;
  575. {
  576.   FILE *fp;
  577.   char c;
  578.   int i, wedge, ring, orient, practice, moves;
  579.   mballCallbackStruct cb;
  580.  
  581.   if ((fp = fopen(DATAFILE, "r")) == NULL)
  582.     (void) printf("Can not read %s for get.\n", DATAFILE);
  583.   else {
  584.     FlushMoves(w);
  585.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  586.     (void) fscanf(fp, "%d", &wedge);
  587.     if (wedge >= MINWEDGES && wedge <= MAXWEDGES && !(wedge % 2)) {
  588.       if (w->mball.wedges != wedge) {
  589.         cb.reason = (wedge - MINWEDGES) / 2 + MBALL_WEDGE2;
  590.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  591.       }
  592.     } else
  593.       (void) printf("%s corrupted: ", DATAFILE);
  594.       (void) printf("wedge %d should be even and between %d and %d\n",
  595.          wedge, MINWEDGES, MAXWEDGES);
  596.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  597.     (void) fscanf(fp, "%d", &ring);
  598.     if (ring >= MINRINGS) {
  599.       for (i = w->mball.rings; i < ring; i++) {
  600.         cb.reason = MBALL_INC;
  601.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  602.       }
  603.       for (i = w->mball.rings; i > ring; i--) {
  604.         cb.reason = MBALL_DEC;
  605.         XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  606.       }
  607.     } else
  608.       (void) printf("%s corrupted: ring %d should be between %d and MAXINT\n",
  609.          DATAFILE, ring, MINRINGS);
  610.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  611.     (void) fscanf(fp, "%d", &orient);
  612.     if (w->mball.orient != (Boolean) orient) {
  613.       cb.reason = MBALL_ORIENT;
  614.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  615.     }
  616.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  617.     (void) fscanf(fp, "%d", &practice);
  618.     if (w->mball.practice != (Boolean) practice) {
  619.       cb.reason = MBALL_PRACTICE;
  620.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  621.     }
  622.     while ((c = getc(fp)) != EOF && c != SYMBOL);
  623.     (void) fscanf(fp, "%d", &moves);
  624.     ScanStartPosition(fp, w);
  625.     cb.reason = MBALL_RESTORE;
  626.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  627.     SetStartPosition(w);
  628.     ScanMoves(fp, w, moves);
  629.     (void) fclose(fp);
  630.     (void) printf("%s: wedge %d, ring %d, orient %d, ",
  631.       DATAFILE, wedge, ring, orient);
  632.     (void) printf("practice %d, moves %d", practice, moves);
  633.   }
  634. }
  635.  
  636. static void WriteMball(w, event, args, nArgs)
  637.   MballWidget w;
  638.   XEvent *event;
  639.   char *args[];
  640.   int nArgs;
  641. {
  642.   FILE *fp;
  643.  
  644.   if ((fp = fopen(DATAFILE, "w")) == NULL)
  645.     (void) printf("Can not write to %s.\n", DATAFILE);
  646.   else {
  647.     (void) fprintf(fp, "wedge%c %d\n", SYMBOL, w->mball.wedges);
  648.     (void) fprintf(fp, "ring%c %d\n", SYMBOL, w->mball.rings);
  649.     (void) fprintf(fp, "orient%c: %d\n", SYMBOL, (w->mball.orient) ? 1 : 0);
  650.     (void) fprintf(fp, "practice%c %d\n", SYMBOL, (w->mball.practice) ? 1 : 0);
  651.     (void) fprintf(fp, "moves%c %d\n", SYMBOL, NumMoves());
  652.     PrintStartPosition(fp, w);
  653.     PrintMoves(fp);
  654.     (void) fclose(fp);
  655.     (void) printf("Saved to %s.\n", DATAFILE);
  656.   }
  657. }
  658.  
  659. static void UndoMball(w, event, args, nArgs)
  660.   MballWidget w;
  661.   XEvent *event;
  662.   char *args[];
  663.   int nArgs;
  664. {
  665.   if (MadeMoves()) {
  666.     int wedge, ring, direction, control;
  667.  
  668.     GetMove(&wedge, &ring, &direction, &control);
  669.     direction = (direction < COORD) ? ((direction < CUTS) ?
  670.       (direction + CUTS / 2) % CUTS :
  671.       (direction + CUTS / 2) % CUTS + CUTS) : 3 * COORD - direction;
  672.     if (control)
  673.       MoveControlCb(w, wedge, direction);
  674.     else {
  675.       mballCallbackStruct cb;
  676.  
  677.       MoveWedges(w, wedge, ring, direction);
  678.       cb.reason = MBALL_UNDO;
  679.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  680.     }
  681.   }
  682. }
  683.  
  684. static void SolveMball(w, event, args, nArgs)
  685.   MballWidget w;
  686.   XEvent *event;
  687.   char *args[];
  688.   int nArgs;
  689. {
  690.   /* SolveWedges(w); */ /* Sorry, unimplemented */
  691. }
  692.  
  693. static void IncrementMball(w, event, args, nArgs)
  694.   MballWidget w;
  695.   XEvent *event;
  696.   char *args[];
  697.   int nArgs;
  698. {
  699.   mballCallbackStruct cb;
  700.  
  701.   cb.reason = MBALL_INC;
  702.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  703. }
  704.  
  705. static void DecrementMball(w, event, args, nArgs)
  706.   MballWidget w;
  707.   XEvent *event;
  708.   char *args[];
  709.   int nArgs;
  710. {
  711.   mballCallbackStruct cb;
  712.  
  713.   if (w->mball.rings <= MINRINGS)
  714.     return;
  715.   cb.reason = MBALL_DEC;
  716.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  717. }
  718.  
  719. static void OrientizeMball(w, event, args, nArgs)
  720.   MballWidget w;
  721.   XEvent *event;
  722.   char *args[];
  723.   int nArgs;
  724. {
  725.   mballCallbackStruct cb;
  726.  
  727.   cb.reason = MBALL_ORIENT;
  728.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  729. }
  730.  
  731. static void Wedge2ModeMball(w, event, args, nArgs)
  732.   MballWidget w;
  733.   XEvent *event;
  734.   char *args[];
  735.   int nArgs;
  736. {
  737.   mballCallbackStruct cb;
  738.  
  739.   cb.reason = MBALL_WEDGE2;
  740.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  741. }
  742.  
  743. static void Wedge4ModeMball(w, event, args, nArgs)
  744.   MballWidget w;
  745.   XEvent *event;
  746.   char *args[];
  747.   int nArgs;
  748. {
  749.   mballCallbackStruct cb;
  750.  
  751.   cb.reason = MBALL_WEDGE4;
  752.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  753. }
  754.  
  755. static void Wedge6ModeMball(w, event, args, nArgs)
  756.   MballWidget w;
  757.   XEvent *event;
  758.   char *args[];
  759.   int nArgs;
  760. {
  761.   mballCallbackStruct cb;
  762.  
  763.   cb.reason = MBALL_WEDGE6;
  764.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  765. }
  766.  
  767. static void Wedge8ModeMball(w, event, args, nArgs)
  768.   MballWidget w;
  769.   XEvent *event;
  770.   char *args[];
  771.   int nArgs;
  772. {
  773.   mballCallbackStruct cb;
  774.  
  775.   cb.reason = MBALL_WEDGE8;
  776.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  777. }
  778.  
  779. static void MoveMballCcw(w, event, args, nArgs)
  780.   MballWidget w;
  781.   XEvent *event;
  782.   char *args[];
  783.   int nArgs;
  784. {
  785.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, CCW,
  786.     (int) (event->xbutton.state & ControlMask));
  787. }
  788.  
  789. static void MoveMballTl(w, event, args, nArgs)
  790.   MballWidget w;
  791.   XEvent *event;
  792.   char *args[];
  793.   int nArgs;
  794. {
  795.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, TL,
  796.     (int) (event->xkey.state & ControlMask));
  797. }
  798.  
  799. static void MoveMballTop(w, event, args, nArgs)
  800.   MballWidget w;
  801.   XEvent *event;
  802.   char *args[];
  803.   int nArgs;
  804. {
  805.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, TOP,
  806.     (int) (event->xkey.state & ControlMask));
  807. }
  808.  
  809. static void MoveMballTr(w, event, args, nArgs)
  810.   MballWidget w;
  811.   XEvent *event;
  812.   char *args[];
  813.   int nArgs;
  814. {
  815.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, TR,
  816.     (int) (event->xkey.state & ControlMask));
  817. }
  818.  
  819. static void MoveMballLeft(w, event, args, nArgs)
  820.   MballWidget w;
  821.   XEvent *event;
  822.   char *args[];
  823.   int nArgs;
  824. {
  825.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, LEFT,
  826.     (int) (event->xkey.state & ControlMask));
  827. }
  828.  
  829. static void MoveMballCw(w, event, args, nArgs)
  830.   MballWidget w;
  831.   XEvent *event;
  832.   char *args[];
  833.   int nArgs;
  834. {
  835.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, CW,
  836.     (int) (event->xkey.state & ControlMask));
  837. }
  838.  
  839. static void MoveMballRight(w, event, args, nArgs)
  840.   MballWidget w;
  841.   XEvent *event;
  842.   char *args[];
  843.   int nArgs;
  844. {
  845.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, RIGHT,
  846.     (int) (event->xkey.state & ControlMask));
  847. }
  848.  
  849. static void MoveMballBl(w, event, args, nArgs)
  850.   MballWidget w;
  851.   XEvent *event;
  852.   char *args[];
  853.   int nArgs;
  854. {
  855.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, BL,
  856.     (int) (event->xkey.state & ControlMask));
  857. }
  858.  
  859. static void MoveMballBottom(w, event, args, nArgs)
  860.   MballWidget w;
  861.   XEvent *event;
  862.   char *args[];
  863.   int nArgs;
  864. {
  865.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, BOTTOM,
  866.     (int) (event->xkey.state & ControlMask));
  867. }
  868.  
  869. static void MoveMballBr(w, event, args, nArgs)
  870.   MballWidget w;
  871.   XEvent *event;
  872.   char *args[];
  873.   int nArgs;
  874. {
  875.   MoveMballInput(w, event->xbutton.x, event->xbutton.y, BR,
  876.     (int) (event->xkey.state & ControlMask));
  877. }
  878.  
  879. static void MoveMballInput(w, x, y, direction, control)
  880.   MballWidget w;
  881.   int x, y, direction, control;
  882. {
  883.   int wedge, ring;
  884.  
  885.   if (CheckSolved(w) && !w->mball.practice && !control) {
  886.     MoveNoWedges(w);
  887.     return;
  888.   }
  889.   if (!PositionWedges(w, x, y, &wedge, &ring, &direction))
  890.     return;
  891.   control = (control) ? 1 : 0;
  892.   MoveMball(w, wedge, ring, direction, control);
  893.   if (!control && CheckSolved(w)) {
  894.     mballCallbackStruct cb;
  895.  
  896.     cb.reason = MBALL_SOLVED;
  897.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  898.   }
  899. }
  900.  
  901. void MoveMball(w, wedge, ring, direction, control)
  902.   MballWidget w;
  903.   int wedge, ring, direction, control;
  904. {
  905.   mballCallbackStruct cb;
  906.  
  907.   if (control)
  908.     MoveControlCb(w, wedge, direction);
  909.   else {
  910.     MoveWedges(w, wedge, ring, direction);
  911.     cb.reason = MBALL_MOVED;
  912.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  913.   }
  914.   PutMove(wedge, ring, direction, control);
  915. }
  916.  
  917. static void GetColor(w, wedge, init)
  918.   MballWidget w;
  919.   int wedge, init;
  920. {
  921.   XGCValues values;
  922.   XtGCMask valueMask;
  923.   XColor colorCell, rgb;
  924.  
  925.   valueMask = GCForeground | GCBackground;
  926.   values.background = w->core.background_pixel;
  927.   if (w->mball.depth > 1 && !w->mball.mono) {
  928.     if (XAllocNamedColor(XtDisplay(w),
  929.         DefaultColormap(XtDisplay(w), XtWindow(w)),
  930.         w->mball.wedgeName[wedge], &colorCell, &rgb)) {
  931.       values.foreground = w->mball.wedgeColor[wedge] = colorCell.pixel;
  932.       if (!init)
  933.         XtReleaseGC((Widget) w, w->mball.wedgeGC[wedge]);
  934.       w->mball.wedgeGC[wedge] = XtGetGC((Widget) w, valueMask, &values);
  935.       return;
  936.     } else {
  937.       char buf[121];
  938.  
  939.       (void) sprintf(buf, "Color name \"%s\" is not defined %d",
  940.                w->mball.wedgeName[wedge], wedge);
  941.       XtWarning(buf);
  942.     }
  943.   }
  944.   values.foreground = w->mball.foreground;
  945.   if (!init)
  946.     XtReleaseGC((Widget) w, w->mball.wedgeGC[wedge]);
  947.   w->mball.wedgeGC[wedge] = XtGetGC((Widget) w, valueMask, &values);
  948. }
  949.  
  950. static void MoveControlCb(w, wedge, direction)
  951.   MballWidget w;
  952.   int wedge, direction;
  953. {
  954.   mballCallbackStruct cb;
  955.   int ring;
  956.  
  957.   if (direction > COORD)
  958.     for (ring = 0; ring < w->mball.rings; ring++) {
  959.       MoveWedges(w, wedge, ring, direction);
  960.       cb.reason = MBALL_CONTROL;
  961.       XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  962.     }
  963.   else {
  964.     MoveWedges(w, 0, 0, direction);
  965.     cb.reason = MBALL_CONTROL;
  966.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  967.     MoveWedges(w, w->mball.wedges / 2, 0, direction);
  968.     cb.reason = MBALL_CONTROL;
  969.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  970.   }
  971. }
  972.  
  973. static void CheckWedges(w)
  974.   MballWidget w;
  975. {
  976.   if (w->mball.wedges < MINWEDGES || w->mball.wedges > MAXWEDGES ||
  977.       w->mball.wedges % 2) {
  978.     char buf[121];
  979.  
  980.     (void) sprintf(buf,
  981.       "Number of wedges out of bounds, use even %d..%d", MINWEDGES, MAXWEDGES);
  982.     XtWarning(buf);
  983.     w->mball.wedges = DEFAULTWEDGES;
  984.   }
  985.   if (w->mball.rings < MINRINGS) {
  986.     char buf[121];
  987.  
  988.     (void) sprintf(buf,
  989.       "Number of rings out of bounds, use %d..MAXINT", MINRINGS);
  990.     XtWarning(buf);
  991.     w->mball.rings = DEFAULTRINGS;
  992.   }
  993. }
  994.  
  995. static void ResetWedges(w)
  996.   MballWidget w;
  997. {
  998.   int wedge, ring;
  999.  
  1000.   for (wedge = 0; wedge < MAXWEDGES; wedge++) {
  1001.     if (w->mball.mballLoc[wedge])
  1002.       (void) free((void *) w->mball.mballLoc[wedge]);
  1003.     if (!(w->mball.mballLoc[wedge] = (MballLoc *)
  1004.           malloc(sizeof(MballLoc) * w->mball.rings)))
  1005.       XtError("Not enough memory, exiting.");
  1006.     if (startLoc[wedge])
  1007.       (void) free((void *) startLoc[wedge]);
  1008.     if (!(startLoc[wedge] = (MballLoc *)
  1009.           malloc(sizeof(MballLoc) * w->mball.rings)))
  1010.       XtError("Not enough memory, exiting.");
  1011.   }
  1012.   for (wedge = 0; wedge < w->mball.wedges; wedge++)
  1013.     for (ring = 0; ring < w->mball.rings; ring++) {
  1014.       w->mball.mballLoc[wedge][ring].wedge = wedge;
  1015.       w->mball.mballLoc[wedge][ring].direction = DOWN; 
  1016.     }
  1017.   FlushMoves(w);
  1018.   w->mball.started = FALSE;
  1019. }
  1020.  
  1021. static void ResizeWedges(w)
  1022.   MballWidget w;
  1023. {
  1024.   w->mball.mballLength = w->mball.wedgeLength / (2 * w->mball.wedges) -
  1025.     w->mball.delta - 1;
  1026.   w->mball.letterOffset.x = -2;
  1027.   w->mball.letterOffset.y = 4;
  1028.   w->mball.dr = w->mball.wedges;
  1029. }
  1030.  
  1031. static int SelectWedges(w, x, y, wedge, ring, view)
  1032.   MballWidget w;
  1033.   int x, y;
  1034.   int *wedge, *ring, *view;
  1035. {
  1036.   double angle, radius;
  1037.  
  1038.   x -= w->mball.puzzleOffset.x;
  1039.   y -= w->mball.puzzleOffset.y;
  1040.   if (w->mball.vertical && y > w->mball.viewLength - 1) {
  1041.     y -= (w->mball.viewLength - 1);
  1042.     *view = DOWN;
  1043.   } else if (!w->mball.vertical && x > w->mball.viewLength - 1) {
  1044.     x -= (w->mball.viewLength - 1);
  1045.     *view = DOWN;
  1046.   } else
  1047.     *view = UP;
  1048.   x -= (w->mball.wedgeLength + 1) / 2;
  1049.   y -= (w->mball.wedgeLength + 1) / 2;
  1050.   radius = sqrt((double) x * x + y * y);
  1051.   if (y >= 0)
  1052.     angle = atan2((double) -x, (double) y) + M_PI;
  1053.   else if (x < 0)
  1054.     angle = 2 * M_PI - atan2((double) -x, (double) -y);
  1055.   else
  1056.     angle = -atan2((double) -x, (double) -y);
  1057.   *ring = (int) (radius * (double) w->mball.rings /
  1058.     ((double) w->mball.wedgeLength));
  1059.   *wedge = (int) (angle * (double) w->mball.wedges / (2.0 * M_PI));
  1060.   if (*view == DOWN) {
  1061.     if (w->mball.vertical)
  1062.       *wedge = (3 * w->mball.wedges / 2 - 1 - *wedge) % w->mball.wedges;
  1063.     else
  1064.       *wedge = (w->mball.wedges - 1 - *wedge) % w->mball.wedges;
  1065.     *ring = w->mball.rings - 1 - *ring;
  1066.   }
  1067.   if (radius > w->mball.wedgeLength / 2 + w->mball.delta)
  1068.     return FALSE;
  1069.   return TRUE;
  1070. }
  1071.  
  1072. static int PositionWedges(w, x, y, wedge, ring, direction)
  1073.   MballWidget w;
  1074.   int x, y;
  1075.   int *wedge, *ring, *direction;
  1076. {
  1077.   int view, inside;
  1078.  
  1079.   inside = SelectWedges(w, x, y, wedge, ring, &view);
  1080.   if ((*direction == CW || *direction == CCW) && !inside)
  1081.     return FALSE;
  1082.   if (view == DOWN) {
  1083.     if (*direction == CCW)
  1084.       *direction = CW;
  1085.     else if (*direction == CW)
  1086.       *direction = CCW;
  1087.     else if (*direction < COORD)
  1088.       *direction = (COORD - *direction) % COORD;
  1089.   }
  1090.   if (w->mball.wedges % 4 && (*direction == LEFT || *direction == RIGHT))
  1091.     return FALSE;
  1092.   if (w->mball.wedges <= 4 && *direction % 2 && *direction < COORD)
  1093.     return FALSE;
  1094.   return TRUE;
  1095. }
  1096.  
  1097. static void MoveNoWedges(w)
  1098.   MballWidget w;
  1099. {
  1100.   mballCallbackStruct cb;
  1101.  
  1102.   cb.reason = MBALL_ILLEGAL;
  1103.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1104. }
  1105.  
  1106. static void PracticeWedges(w)
  1107.   MballWidget w;
  1108. {
  1109.   mballCallbackStruct cb;
  1110.  
  1111.   cb.reason = MBALL_PRACTICE;
  1112.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1113. }
  1114.  
  1115. static void RandomizeWedges(w)
  1116.   MballWidget w;
  1117. {
  1118.   mballCallbackStruct cb;
  1119.   int randomDirection, wedge, ring;
  1120.   int big = w->mball.wedges * (w->mball.rings + 1) + NRAND(2);
  1121.  
  1122.   if (big > 100)
  1123.     big = 100;
  1124.   if (w->mball.practice)
  1125.     PracticeWedges(w);
  1126.   cb.reason = MBALL_RESET;
  1127.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1128.  
  1129. #ifdef DEBUG
  1130.   big = 3;
  1131. #endif
  1132.  
  1133.   while (big--) {
  1134.     wedge = NRAND(w->mball.wedges);
  1135.     ring = NRAND(w->mball.rings);
  1136.     do
  1137.       randomDirection = NRAND(2 * COORD);
  1138.     while (randomDirection < COORD &&
  1139.            mapDirToWedge[(w->mball.wedges - MINWEDGES) / 2][randomDirection] ==
  1140.              CUTS);
  1141.     if (randomDirection >= COORD) {
  1142.       if (randomDirection - COORD < CUTS)
  1143.         randomDirection = CW;
  1144.       else
  1145.         randomDirection = CCW;
  1146.     }
  1147.     MoveMball(w, wedge, ring, randomDirection, FALSE);
  1148.   }
  1149.   FlushMoves(w);
  1150.   cb.reason = MBALL_RANDOMIZE;
  1151.   XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1152.   if (CheckSolved(w)) {
  1153.     cb.reason = MBALL_SOLVED;
  1154.     XtCallCallbacks((Widget) w, XtNselectCallback, &cb);
  1155.   }
  1156. }
  1157.  
  1158. static void SwapWedges(w, wedge1, wedge2)
  1159.   MballWidget w;
  1160.   int wedge1, wedge2;
  1161. {
  1162.   MballLoc temp;
  1163.   int ring;
  1164.  
  1165.   if (wedge1 == wedge2) {
  1166.     for (ring = 0; ring < w->mball.rings / 2; ring++) {
  1167.       temp = w->mball.mballLoc[wedge1][ring];
  1168.       w->mball.mballLoc[wedge1][ring] =
  1169.         w->mball.mballLoc[wedge1][w->mball.rings - 1 - ring];
  1170.       w->mball.mballLoc[wedge1][w->mball.rings - 1 - ring] = temp;
  1171.     }
  1172.     for (ring = 0; ring < w->mball.rings; ring++) 
  1173.       w->mball.mballLoc[wedge1][ring].direction =
  1174.         !w->mball.mballLoc[wedge1][ring].direction;
  1175.     DrawWedge(w, wedge1);
  1176.   } else {
  1177.     for (ring = 0; ring < w->mball.rings; ring++) {
  1178.       temp = w->mball.mballLoc[wedge1][ring];
  1179.       w->mball.mballLoc[wedge1][ring] =
  1180.         w->mball.mballLoc[wedge2][w->mball.rings - 1 - ring];
  1181.       w->mball.mballLoc[wedge2][w->mball.rings - 1 - ring] = temp;
  1182.       w->mball.mballLoc[wedge1][ring].direction =
  1183.         !w->mball.mballLoc[wedge1][ring].direction;
  1184.       w->mball.mballLoc[wedge2][w->mball.rings - 1 - ring].direction =
  1185.         !w->mball.mballLoc[wedge2][w->mball.rings - 1 - ring].direction;
  1186.     }
  1187.     DrawWedge(w, wedge1);
  1188.     DrawWedge(w, wedge2);
  1189.   }
  1190. }
  1191.  
  1192. static void MoveWedges(w, wedge, ring, direction)
  1193.   MballWidget w;
  1194.   int wedge, ring, direction;
  1195. {
  1196.   int i;
  1197.  
  1198.   if (direction == CW || direction == CCW) { /* rotate ring */
  1199.     int newI;
  1200.     MballLoc temp1, temp2;
  1201.     for (i = 0; i < w->mball.wedges; i++) {
  1202.       newI = (direction == CW) ? i : w->mball.wedges - 1 - i;
  1203.       if (newI == ((direction == CW) ? 0 : w->mball.wedges - 1)) {
  1204.         temp1 = w->mball.mballLoc[newI][ring]; 
  1205.         w->mball.mballLoc[newI][ring] = w->mball.mballLoc
  1206.           [((direction == CW) ? w->mball.wedges - 1 : 0)][ring];
  1207.       } else {
  1208.         temp2 = temp1;
  1209.         temp1 = w->mball.mballLoc[newI][ring];
  1210.         w->mball.mballLoc[newI][ring] = temp2;
  1211.       }
  1212.       DrawSector(w, newI, ring, FALSE);
  1213.     }
  1214.   } else { /* flip */
  1215.     int sphereDir = mapDirToWedge[(w->mball.wedges - MINWEDGES) / 2][direction];
  1216.     int offset = w->mball.wedges / 2;
  1217.     int wedge1, wedge2;
  1218.  
  1219.     for (i = 0; i < w->mball.wedges / 2; i++)
  1220.       if (wedge == i + sphereDir)
  1221.         offset = 0;
  1222.     for (i = 0; i < (w->mball.wedges + 2) / 4; i++) {
  1223.       wedge1 = (i + sphereDir + offset) % w->mball.wedges;
  1224.       wedge2 = (w->mball.wedges / 2 - 1 - i + sphereDir + offset) %
  1225.         w->mball.wedges;
  1226.       SwapWedges(w, wedge1, wedge2);
  1227.     }
  1228.   }
  1229. }
  1230.  
  1231. static void DrawFrame(w, gc)
  1232.   MballWidget w;
  1233.   GC gc;
  1234. {
  1235.   int startx, starty, lengthx, lengthy;
  1236.  
  1237.   startx = 1 + w->mball.puzzleOffset.x;
  1238.   starty = 1 + w->mball.puzzleOffset.y;
  1239.   lengthx = w->mball.viewLength - w->mball.delta + w->mball.puzzleOffset.x;
  1240.   lengthy = w->mball.viewLength - w->mball.delta + w->mball.puzzleOffset.y;
  1241.   DrawRadar(w, gc, startx, starty, lengthx - startx, lengthy - starty);
  1242.   if (w->mball.vertical) {
  1243.     XDrawLine(XtDisplay(w), XtWindow(w), gc, 0, lengthy + 1,
  1244.       (int) w->core.width - 1, lengthy + 1);
  1245.     DrawRadar(w, gc, startx, lengthy + 3, lengthx - startx, lengthy - starty);
  1246.   } else {
  1247.     XDrawLine(XtDisplay(w), XtWindow(w), gc, lengthx + 1, 0,
  1248.       lengthx + 1, (int) w->core.height - 1);
  1249.     DrawRadar(w, gc, lengthx + 3, starty, lengthx - startx, lengthy - starty);
  1250.   }
  1251. }   
  1252.  
  1253. void DrawAllWedges(w)
  1254.   MballWidget w;
  1255. {
  1256.   int wedge;
  1257.  
  1258.   for (wedge = 0; wedge < w->mball.wedges; wedge++)
  1259.     DrawWedge(w, wedge);
  1260. }
  1261.  
  1262. static void DrawWedge(w, wedge)
  1263.   MballWidget w;
  1264.   int wedge;
  1265. {
  1266.   int ring;
  1267.  
  1268.   for (ring = 0; ring < w->mball.rings; ring++)
  1269.     DrawSector(w, wedge, ring, FALSE);
  1270. }
  1271.  
  1272. static void LetterPosition(w, wedge, ring, lengthx, lengthy, dx, dy)
  1273.   MballWidget w;
  1274.   int wedge, ring, lengthx, lengthy, *dx, *dy;
  1275. {
  1276.   double angle, radius;
  1277.  
  1278.   angle = (double) (2 * wedge + 1) * M_PI / w->mball.wedges;
  1279.   if (w->mball.rings % 2 && ring == w->mball.rings / 2)
  1280.     radius = ((double) 4.0 * ring + 1.0) / ((double) 4.0 * w->mball.rings);
  1281.   else
  1282.     radius = ((double) 2.0 * ring + 1.0) / ((double) 2.0 * w->mball.rings);
  1283.   *dx = lengthx / 2 + (int) ((double) lengthx * radius * cos(angle - M_PI / 2));
  1284.   *dy = lengthy / 2 + (int) ((double) lengthy * radius * sin(angle - M_PI / 2));
  1285. }
  1286.  
  1287. static void OffsetSect(w, wedge, dx, dy)
  1288.   MballWidget w;
  1289.   int wedge;
  1290.   int *dx, *dy;
  1291. {
  1292.   double angle = (double) (2 * wedge + 1) * M_PI / w->mball.wedges;
  1293.  
  1294.   *dx = (int) ((double) w->mball.dr * cos(angle - M_PI / 2));
  1295.   *dy = (int) ((double) w->mball.dr * sin(angle - M_PI / 2));
  1296. }
  1297.  
  1298. static void DrawSector(w, wedge, ring, offset)
  1299.   MballWidget w;
  1300.   int wedge, ring, offset;
  1301. {
  1302.   int startx, starty, lengthx, lengthy;
  1303.  
  1304.   startx = 1 + w->mball.puzzleOffset.x;
  1305.   starty = 1 + w->mball.puzzleOffset.y;
  1306.   lengthx = w->mball.viewLength - w->mball.delta + w->mball.puzzleOffset.x;
  1307.   lengthy = w->mball.viewLength - w->mball.delta + w->mball.puzzleOffset.y;
  1308.   if (ring < (w->mball.rings + 1) / 2)
  1309.     if (offset)
  1310.       DrawSect(w, w->mball.borderGC,
  1311.         w->mball.wedgeGC[w->mball.mballLoc[wedge][ring].wedge], ring, wedge,
  1312.       startx, starty, lengthx - startx, lengthy - starty);
  1313.     else
  1314.       DrawSect(w, w->mball.wedgeGC[w->mball.mballLoc[wedge][ring].wedge],
  1315.         w->mball.borderGC, ring, wedge,
  1316.         startx, starty, lengthx - startx, lengthy - starty);
  1317.   if (ring + 1 > w->mball.rings / 2) {
  1318.     if (w->mball.vertical)
  1319.       if (offset)
  1320.         DrawSect(w, w->mball.borderGC,
  1321.           w->mball.wedgeGC[w->mball.mballLoc[wedge][ring].wedge],
  1322.           w->mball.rings - 1 - ring,
  1323.           (3 * w->mball.wedges / 2 - 1 - wedge) % w->mball.wedges,
  1324.           startx, lengthy + 3, lengthx - startx, lengthy - starty);
  1325.       else
  1326.         DrawSect(w, w->mball.wedgeGC[w->mball.mballLoc[wedge][ring].wedge],
  1327.           w->mball.borderGC, w->mball.rings - 1 - ring,
  1328.           (3 * w->mball.wedges / 2 - 1 - wedge) % w->mball.wedges,
  1329.           startx, lengthy + 3, lengthx - startx, lengthy - starty);
  1330.     else
  1331.       if (offset)
  1332.         DrawSect(w, w->mball.borderGC,
  1333.           w->mball.wedgeGC[w->mball.mballLoc[wedge][ring].wedge],
  1334.           w->mball.rings - 1 - ring, w->mball.wedges - 1 - wedge,
  1335.           lengthx + 3, starty, lengthx - startx, lengthy - starty);
  1336.       else
  1337.         DrawSect(w, w->mball.wedgeGC[w->mball.mballLoc[wedge][ring].wedge],
  1338.           w->mball.borderGC,
  1339.           w->mball.rings - 1 - ring, w->mball.wedges - 1 - wedge,
  1340.           lengthx + 3, starty, lengthx - startx, lengthy - starty);
  1341.   }
  1342.   if (w->mball.depth == 1 || w->mball.mono) {
  1343.     int letterX, letterY;
  1344.     char buf[3];
  1345.  
  1346.     if (ring < (w->mball.rings + 1) / 2) {
  1347.       LetterPosition(w, wedge, ring, lengthx - startx, lengthy - starty,
  1348.         &letterX, &letterY);
  1349.       letterX += startx + w->mball.letterOffset.x;
  1350.       letterY += starty + w->mball.letterOffset.y;
  1351.       if (w->mball.orient && !w->mball.mballLoc[wedge][ring].direction) {
  1352.         (void) sprintf(buf, "%d%c", w->mball.mballLoc[wedge][ring].wedge,
  1353.           w->mball.wedgeName[w->mball.mballLoc[wedge][ring].wedge][0]);
  1354.         letterX += w->mball.letterOffset.x;
  1355.         XDrawString(XtDisplay(w), XtWindow(w), w->mball.inverseGC,
  1356.           letterX, letterY, buf, 2);
  1357.       } else {
  1358.         (void) sprintf(buf, "%c",
  1359.           w->mball.wedgeName[w->mball.mballLoc[wedge][ring].wedge][0]);
  1360.         XDrawString(XtDisplay(w), XtWindow(w), w->mball.inverseGC,
  1361.           letterX, letterY, buf, 1);
  1362.       }
  1363.     }
  1364.     if (ring + 1 > w->mball.rings / 2) {
  1365.       if (w->mball.vertical) {
  1366.         LetterPosition(w,
  1367.           (3 * w->mball.wedges / 2 - 1 - wedge) % w->mball.wedges,
  1368.           w->mball.rings - 1 - ring,
  1369.           lengthx - startx, lengthy - starty,
  1370.           &letterX, &letterY);
  1371.         letterX += startx + w->mball.letterOffset.x;
  1372.         letterY += lengthy + 3 + w->mball.letterOffset.y;
  1373.       } else {
  1374.         LetterPosition(w,
  1375.           w->mball.wedges - 1 - wedge,
  1376.           w->mball.rings - 1 - ring,
  1377.           lengthx - startx, lengthy - starty,
  1378.           &letterX, &letterY);
  1379.         letterX += lengthx + 3 + w->mball.letterOffset.x;
  1380.         letterY += starty + w->mball.letterOffset.y;
  1381.       }
  1382.       if (w->mball.orient && w->mball.mballLoc[wedge][ring].direction) {
  1383.         (void) sprintf(buf, "%d%c", w->mball.mballLoc[wedge][ring].wedge,
  1384.           w->mball.wedgeName[w->mball.mballLoc[wedge][ring].wedge][0]);
  1385.         letterX += w->mball.letterOffset.x;
  1386.         XDrawString(XtDisplay(w), XtWindow(w), w->mball.inverseGC,
  1387.           letterX, letterY, buf, 2);
  1388.       } else {
  1389.         (void) sprintf(buf, "%c",
  1390.           w->mball.wedgeName[w->mball.mballLoc[wedge][ring].wedge][0]);
  1391.         XDrawString(XtDisplay(w), XtWindow(w), w->mball.inverseGC,
  1392.           letterX, letterY, buf, 1);
  1393.       }
  1394.     }
  1395.   } else if (w->mball.orient) {
  1396.     int letterX, letterY;
  1397.     char buf[2];
  1398.  
  1399.     if (ring < (w->mball.rings + 1) / 2 &&
  1400.         !w->mball.mballLoc[wedge][ring].direction) {
  1401.       LetterPosition(w, wedge, ring, lengthx - startx, lengthy - starty,
  1402.         &letterX, &letterY);
  1403.       letterX += startx + w->mball.letterOffset.x;
  1404.       letterY += starty + w->mball.letterOffset.y;
  1405.       (void) sprintf(buf, "%d", w->mball.mballLoc[wedge][ring].wedge);
  1406.       XDrawString(XtDisplay(w), XtWindow(w), w->mball.inverseGC,
  1407.         letterX, letterY, buf, 1);
  1408.     }
  1409.     if (ring + 1 > w->mball.rings / 2 &&
  1410.         w->mball.mballLoc[wedge][ring].direction) {
  1411.       if (w->mball.vertical) {
  1412.         LetterPosition(w,
  1413.           (3 * w->mball.wedges / 2 - 1 - wedge) % w->mball.wedges,
  1414.           w->mball.rings - 1 - ring,
  1415.           lengthx - startx, lengthy - starty,
  1416.           &letterX, &letterY);
  1417.         letterX += startx + w->mball.letterOffset.x;
  1418.         letterY += lengthy + 3 + w->mball.letterOffset.y;
  1419.       } else {
  1420.         LetterPosition(w,
  1421.           w->mball.wedges - 1 - wedge,
  1422.           w->mball.rings - 1 - ring,
  1423.           lengthx - startx, lengthy - starty,
  1424.           &letterX, &letterY);
  1425.         letterX += lengthx + 3 + w->mball.letterOffset.x;
  1426.         letterY += starty + w->mball.letterOffset.y;
  1427.       }
  1428.       (void) sprintf(buf, "%d", w->mball.mballLoc[wedge][ring].wedge);
  1429.       XDrawString(XtDisplay(w), XtWindow(w), w->mball.inverseGC,
  1430.         letterX, letterY, buf, 1);
  1431.     }
  1432.   }
  1433. }
  1434.  
  1435. static void DrawRadar(w, gc, startx, starty, lengthx, lengthy)
  1436.   MballWidget w;
  1437.   GC gc;
  1438.   int startx, starty, lengthx, lengthy;
  1439. {
  1440.   int r, i;
  1441.   double angle, increment;
  1442.  
  1443.   XDrawArc(XtDisplay(w), XtWindow(w), gc, startx, starty,
  1444.     lengthx, lengthy, 0, CIRCLE);
  1445.   if (w->mball.rings % 2)
  1446.     for (r = 1; r < w->mball.rings / 2 + 1; r++)
  1447.       XDrawArc(XtDisplay(w), XtWindow(w), gc,
  1448.         startx - lengthx / (2 * w->mball.rings) +
  1449.           (w->mball.rings / 2 + 1 - r) * lengthx / w->mball.rings,
  1450.         starty - lengthy / (2 * w->mball.rings) +
  1451.           (w->mball.rings / 2 + 1 - r) * lengthy / w->mball.rings,
  1452.         r * 2 * lengthx / w->mball.rings,
  1453.         r * 2 * lengthy / w->mball.rings,
  1454.         0, CIRCLE);
  1455.   else
  1456.     for (r = 1; r < w->mball.rings / 2; r++)
  1457.       XDrawArc(XtDisplay(w), XtWindow(w), gc,
  1458.         startx + (w->mball.rings / 2 - r) * lengthx / w->mball.rings,
  1459.         starty + (w->mball.rings / 2 - r) * lengthy / w->mball.rings,
  1460.         r * 2 * lengthx / w->mball.rings,
  1461.         r * 2 * lengthy / w->mball.rings,
  1462.         0, CIRCLE);
  1463.   increment = RADIANS(NUM_DEGREES) / (double) w->mball.wedges;
  1464.   angle = RADIANS(RT_ANG);
  1465.   for (i = 0; i < w->mball.wedges; i++) {
  1466.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  1467.       startx + lengthx / 2, starty + lengthy / 2,
  1468.       startx + lengthx / 2 + (int) ((double) lengthx * cos(angle) / 2.0),
  1469.       starty + lengthy / 2 + (int) ((double) lengthy * sin(angle) / 2.0));
  1470.     angle += increment;
  1471.   }
  1472. }
  1473.  
  1474. static void DrawSect(w, wedgeGC, borderGC,
  1475.     r, wedge, startx, starty, lengthx, lengthy)
  1476.   MballWidget w;
  1477.   GC wedgeGC, borderGC;
  1478.   int r, wedge;
  1479.   int startx, starty, lengthx, lengthy;
  1480. {
  1481.   int dx, dy;
  1482.  
  1483.   OffsetSect(w, wedge, &dx, &dy);
  1484.   if (w->mball.rings % 2) {
  1485.     if (r == w->mball.rings / 2) {
  1486.       XFillSector(XtDisplay(w), XtWindow(w), wedgeGC,
  1487.         startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
  1488.         r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1489.         r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1490.         (r + 1) * 2 * lengthx / (w->mball.rings + 1) - 2 * w->mball.dr,
  1491.         (r + 1) * 2 * lengthy / (w->mball.rings + 1) - 2 * w->mball.dr,
  1492.         CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
  1493.         -CIRCLE / w->mball.wedges);
  1494.       XDrawSector(XtDisplay(w), XtWindow(w), borderGC,
  1495.         startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
  1496.         r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1497.         r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1498.         (r + 1) * 2 * lengthx / (w->mball.rings + 1) - 2 * w->mball.dr,
  1499.         (r + 1) * 2 * lengthy / (w->mball.rings + 1) - 2 * w->mball.dr,
  1500.         CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
  1501.         -CIRCLE / w->mball.wedges);
  1502.     } else {
  1503.       XFillSector(XtDisplay(w), XtWindow(w), wedgeGC,
  1504.         startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
  1505.         r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1506.         r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1507.         (r + 1) * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1508.         (r + 1) * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1509.         CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
  1510.         -CIRCLE / w->mball.wedges);
  1511.       XDrawSector(XtDisplay(w), XtWindow(w), borderGC,
  1512.         startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
  1513.         r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1514.         r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1515.         (r + 1) * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1516.         (r + 1) * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1517.         CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
  1518.         -CIRCLE / w->mball.wedges);
  1519.     }
  1520.   } else {
  1521.     XFillSector(XtDisplay(w), XtWindow(w), wedgeGC,
  1522.       startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
  1523.       r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1524.       r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1525.       (r + 1) * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1526.       (r + 1) * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1527.       CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
  1528.       -CIRCLE / w->mball.wedges);
  1529.     XDrawSector(XtDisplay(w), XtWindow(w), borderGC,
  1530.       startx + lengthx / 2 + dx, starty + lengthy / 2 + dy,
  1531.       r * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1532.       r * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1533.       (r + 1) * 2 * lengthx / w->mball.rings - 2 * w->mball.dr,
  1534.       (r + 1) * 2 * lengthy / w->mball.rings - 2 * w->mball.dr,
  1535.       CIRCLE_4 - CIRCLE * wedge / w->mball.wedges,
  1536.       -CIRCLE / w->mball.wedges);
  1537.   }
  1538. }
  1539.  
  1540. static void XFillSector(display, drawable, gc,
  1541.     xo, yo, width1, height1, width2, height2, angle1, angle2)
  1542.   Display *display;
  1543.   Drawable drawable;
  1544.   GC gc;
  1545.   int xo, yo;
  1546.   int width1, height1, width2, height2;
  1547.   int angle1, angle2;
  1548. {
  1549.   int d, r1 = MIN(width1, height1) / 2, r2 = MIN(width2, height2) / 2;
  1550.   int w = MAX(r2 - r1 - 8, 1);
  1551.  
  1552.   if (r1 > r2) {
  1553.     d = r1; r1 = r2; r2 = d;
  1554.   }
  1555.   if (r1 < 0)
  1556.     r1 = -3;
  1557.   d = MAX(r1 + r2 + 2, 2);
  1558.   XSetLineAttributes(display, gc, w, LineSolid, CapNotLast, JoinRound);
  1559.   XDrawArc(display, drawable, gc, xo - d / 2, yo - d / 2, d, d,
  1560.       angle1, angle2);
  1561.   XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinRound);
  1562. }
  1563.  
  1564. static void XDrawSector(display, drawable, gc,
  1565.     xo, yo, width1, height1, width2, height2, angle1, angle2)
  1566.   Display *display;
  1567.   Drawable drawable;
  1568.   GC gc;
  1569.   int xo, yo;
  1570.   int width1, height1, width2, height2;
  1571.   int angle1, angle2;
  1572. {
  1573.   int d, r1 = MIN(width1, height1) / 2, r2 = MIN(width2, height2) / 2;
  1574.   /*double ang, x, y; */
  1575.  
  1576.   if (r1 > r2) {
  1577.     d = r1; r1 = r2; r2 = d;
  1578.   }
  1579.   if (r1 < 0)
  1580.     r1 = -3;
  1581.   d = MAX(2 * (r1 + 3), 1);
  1582.   XDrawArc(display, drawable, gc, xo - d / 2, yo - d / 2, d, d,
  1583.     angle1, angle2);
  1584.   d = MAX(2 * (r2 - 1), 3);
  1585.   XDrawArc(display, drawable, gc, xo - d / 2, yo - d / 2, d, d,
  1586.     angle1, angle2);
  1587.  
  1588.   /*ang = RADIANS((double) angle1 / MULT);
  1589.   x = cos(ang);
  1590.   y = sin(ang);
  1591.   XDrawLine(display, drawable, gc,
  1592.    (int) ((double) r1 * x) + xo, (int) ((double) r1 * y) + yo,
  1593.    (int) ((double) r2 * x) + xo, (int) ((double) r2 * y) + yo);
  1594.   ang = RADIANS((double) angle2 / MULT);
  1595.   x = cos(ang);
  1596.   y = sin(ang);
  1597.   XDrawLine(display, drawable, gc,
  1598.    (int) ((double) r1 * x) + xo, (int) ((double) r1 * y) + yo,
  1599.    (int) ((double) r2 * x) + xo, (int) ((double) r2 * y) + yo);*/
  1600. }
  1601.  
  1602. /*
  1603. static void XFillSector(display, drawable, gc,
  1604.     xo, yo, width1, height1, width2, height2, angle1, angle2)
  1605.   Display *display;
  1606.   Drawable drawable;
  1607.   GC gc;
  1608.   int xo, yo;
  1609.   int width1, height1, width2, height2;
  1610.   int angle1, angle2;
  1611. {
  1612.   int d, r1 = MIN(width1, height1) / 2, r2 = MIN(width2, height2) / 2;
  1613.  
  1614.   if (r1 > r2) {
  1615.     d = r1; r1 = r2; r2 = d;
  1616.   }
  1617.   if (r1 < 0)
  1618.     r1 = -3;
  1619.   for (d = 2 * (r1 + 3); d < 2 * (r2 - 1); d++)
  1620.     XDrawArc(display, drawable, gc, xo - d / 2, yo - d / 2, d, d,
  1621.       angle1, angle2);
  1622. }
  1623. */
  1624. Boolean CheckSolved(w)
  1625.   MballWidget w;
  1626. {
  1627.   int wedge, ring;
  1628.   MballLoc test;
  1629.  
  1630.   if (w->mball.orient)
  1631.     for (wedge = 0; wedge < w->mball.wedges; wedge++) {
  1632.       if (wedge == 0) {
  1633.         test.wedge = w->mball.mballLoc[wedge][0].wedge;
  1634.         test.direction = w->mball.mballLoc[wedge][0].direction;
  1635.       }
  1636.       for (ring = 0; ring < w->mball.rings; ring++) {
  1637.         if (test.direction != w->mball.mballLoc[wedge][ring].direction)
  1638.           return FALSE;
  1639.         if (test.direction) {
  1640.           if ((w->mball.wedges - w->mball.mballLoc[wedge][ring].wedge +
  1641.                test.wedge) % w->mball.wedges != wedge)
  1642.             return FALSE;
  1643.         } else {
  1644.           if ((w->mball.wedges + w->mball.mballLoc[wedge][ring].wedge -
  1645.                test.wedge) % w->mball.wedges != wedge)
  1646.             return FALSE;
  1647.         }
  1648.       }
  1649.     }
  1650.   else
  1651.     for (wedge = 0; wedge < w->mball.wedges; wedge++)
  1652.       for (ring = 0; ring < w->mball.rings; ring++)
  1653.         if (ring == 0) {
  1654.           test.wedge = w->mball.mballLoc[wedge][ring].wedge;
  1655.           test.direction = w->mball.mballLoc[wedge][ring].direction;
  1656.         } else if (test.wedge != w->mball.mballLoc[wedge][ring].wedge)
  1657.           return FALSE;
  1658.   return TRUE;
  1659. }
  1660.  
  1661. #ifdef DEBUG
  1662.  
  1663. static void PrintMball(w)
  1664.   MballWidget w;
  1665. {
  1666.   int wedge, ring;
  1667.  
  1668.   for (wedge = 0; wedge < w->mball.wedges; wedge++) {
  1669.     for (ring = 0; ring < w->mball.rings; ring++) {
  1670.       (void) printf("%d %d  ", w->mball.mballLoc[wedge][ring].wedge,
  1671.                w->mball.mballLoc[wedge][ring].direction);
  1672.     }
  1673.     (void) printf("\n");
  1674.   }
  1675.   (void) printf("\n");
  1676. }
  1677.  
  1678. #endif
  1679.